求教:C#如何实现背景图片的移动?

qq_36198178 2017-03-17 04:24:14
想做一个模拟列车运行的界面,像这样:

考虑后觉得原理应该是:车放一个pictureBox1,而pictureBox2、pictureBox3···放背景图片,让背景图片循环左右平移,而车不动。
但现在遇到两个问题:
1.关于车的图片的背景颜色:应该设置为透明(为了不遮住后面的背景),我先是用了网上的方法:将BackColor设置为Transparent,pictureBox1.Parent = pictureBox2;但这样的话,当背景图片移动的时候,车的图片就随着一起移动了,像这样:

所以想问除此之外,还有什么办法能让车图片的背景透明吗?
2.我能实现一张背景图片的左右平移(如pictureBox2),代码很简单:
this.pictureBox1.Left -= 5;
想问一下:如何实现让pictureBox3、pictureBox4的背景图片衔接着pictureBox2平移下去?我想做到的是pictureBox2——pictureBox3——pictureBox4——pictureBox2——pictureBox3······这样平移。
楼主初学编程,加之比较笨,所以冒昧请教一下这些也许在大牛面前很白痴的问题,烦请不吝赐教,先行谢过了!
...全文
1562 51 打赏 收藏 转发到动态 举报
写回复
用AI写文章
51 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq_36198178 2017-05-08
  • 打赏
  • 举报
回复
不好意思,现在才发现有结贴这一说! 我的点数只有40点,所以只能给直接帮我解决问题的那位,但是也很感谢其他帮我想办法的兄弟!
_jiasong 2017-03-27
  • 打赏
  • 举报
回复
美图秀秀、光影魔术手也都能抠图。
_jiasong 2017-03-27
  • 打赏
  • 举报
回复
不想写代码就ps,直接抠图
  • 打赏
  • 举报
回复
引用 30 楼 qq_36198178 的回复:
[quote=引用 29 楼 xuzuning 的回复:]
        public Region GetRegion(Bitmap bmp)
        {
            Region res = new Region();
            res.MakeEmpty();
            var colorTransparent = bmp.GetPixel(0, 0); //指定左上角为透明色

            var a = Enumerable.Range(0, bmp.Width).ToList();
            var b = Enumerable.Range(0, bmp.Height).ToList();
            var q = from x in a
                    from y in b
                    where bmp.GetPixel(x, y) != colorTransparent
                    select new Rectangle(x, y, 1, 1);
            foreach (var r in q) res.Union(r);
            return res;
        }
你指定
pictureBox1.Region = GetRegion((Bitmap)pictureBox1.Image);
就可以了 不喜欢 linq 的话,就改成双重循环。看着还简单些
版主,我调用这个方法后,出来是这个样子: 这个方法的程序我大概能明白,意思就是颜色和(0,0)点一样的点,编程镂空的,但不知为啥会成为这个样子。 貌似是在车里面选的点,而非是判断pictureBox里面的点[/quote] 还不错嘛
qq_36769535 2017-03-27
  • 打赏
  • 举报
回复
qq_36769535 2017-03-27
  • 打赏
  • 举报
回复
无闪烁,流畅移动,这样肯定没问题。
如果没装Directx就装一个,不过应该都装了。
将Microsoft.DirectX.dll、Microsoft.DirectX.Direct3D.dll、Microsoft.DirectX.Direct3DX.dll
3个文件放到你的文件夹里,(位置在C:\Windows\Microsoft.NET\DirectX for Managed Code\1.0.2902.0)
“引用”添加:Microsoft.DirectX;Microsoft.DirectX.Direct3D;(文件夹里的)
Microsoft.VisualC(程序集里的)3个文件;
修改app.config这一句:
<startup useLegacyV2RuntimeActivationPolicy="true">
就是Dirctx9支持
下面代码直接全部粘贴就行了,坐标位置自己调整

using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace MDX4
{
public class MDX4 : Form
{
Device device = null;
PresentParameters presentParams = new PresentParameters();
float counter;
bool useTransformation = true;
Texture texture;

public MDX4()
{
this.ClientSize = new System.Drawing.Size(640,480);
this.Text = "移动背景 按“T”键重置";
}
public bool InitializeGraphics()
{
try
{
presentParams.Windowed=true;
presentParams.SwapEffect = SwapEffect.Discard;
device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);
device.DeviceReset += new System.EventHandler(this.OnResetDevice);
this.OnResetDevice(device, null);
texture = TextureLoader.FromFile(device,"cloud3.bmp");
return true;
}
catch (DirectXException)
{
return false;
}
}
public void OnResetDevice(object sender, EventArgs e)
{
Device dev = (Device)sender;
dev.RenderState.Lighting = false;
dev.RenderState.DitherEnable = true;
device.RenderState.CullMode = Cull.None;
}
private CustomVertex.PositionTextured[] CreateTransformedQuad()
{
CustomVertex.PositionTextured[] verts = new CustomVertex.PositionTextured[4];
verts[0].Position = new Vector3 ( -1.0f,-1.0f, 3.0f ); verts[0].Tu =0-counter; verts[0].Tv = 1.0f;
verts[1].Position = new Vector3 ( -1.0f, 1.0f, 3.0f ); verts[1].Tu =0-counter; verts[1].Tv = 0.0f;
verts[2].Position = new Vector3 ( 1.0f, -1.0f, 3.0f ); verts[2].Tu =1-counter; verts[2].Tv = 1.0f;
verts[3].Position = new Vector3 ( 1.0f, 1.0f, 3.0f ); verts[3].Tu =1-counter; verts[3].Tv = 0.0f;
return verts;
}
private CustomVertex.PositionTextured[] CreateQuad()
{
CustomVertex.PositionTextured[] verts = new CustomVertex.PositionTextured[4];
verts[0].Position = new Vector3 ( -1.0f,-1.0f, 3.0f ); verts[0].Tu =1.0f; verts[0].Tv = 1.0f;
verts[1].Position = new Vector3 ( -1.0f, 1.0f, 3.0f ); verts[1].Tu =1.0f; verts[1].Tv = 0.0f;
verts[2].Position = new Vector3 ( 1.0f, -1.0f, 3.0f ); verts[2].Tu =0.0f; verts[2].Tv = 1.0f;
verts[3].Position = new Vector3 ( 1.0f, 1.0f, 3.0f ); verts[3].Tu =0.0f; verts[3].Tv = 0.0f;
return verts;
}
private void Render()
{
if (device == null) return;
device.Clear(ClearFlags.Target , System.Drawing.Color.Black, 1.0f, 0);
device.BeginScene();
device.Transform.World = Matrix.Identity;
device.Transform.View = Matrix.LookAtLH ( new Vector3 ( 0, 0, 5f ), new Vector3 ( 0, 0, 0 ), new Vector3 ( 0, 1, 0 ) );
device.Transform.Projection = Matrix.PerspectiveFovLH ( (float)Math.PI / 4, this.Width / this.Height, 1.0f, 100.0f );
device.VertexFormat = CustomVertex.PositionTextured.Format;
device.SetTexture(0,texture);
device.SamplerState[0].AddressU = TextureAddress.Wrap;
if(useTransformation)
{
device.TextureState[0].TextureTransform = TextureTransform.Count2;
Matrix m = Matrix.Identity;
m.M31 = counter;
device.Transform.Texture0 = m;
device.DrawUserPrimitives(PrimitiveType.TriangleStrip,2,CreateQuad());
device.TextureState[0].TextureTransform = TextureTransform.Disable;
}
else
device.DrawUserPrimitives(PrimitiveType.TriangleStrip,2,CreateTransformedQuad());

counter += 0.0015f;
device.EndScene();
device.Present();
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
this.Render();
}

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if(keyData == Keys.Escape)
Application.Exit();
if(keyData == Keys.T)
useTransformation = !useTransformation;

return base.ProcessCmdKey( ref msg, keyData );
}
static void Main()
{
using (MDX4 frm = new MDX4())
{
if (!frm.InitializeGraphics())
{
MessageBox.Show("初始化DirectX失败,程序退出!");
return;
}
frm.Show();
//火车
PictureBox pb = new PictureBox();
pb.Image = Image.FromFile("R_5.bmp");
pb.Location = new Point(100, 100);
pb.Size = new Size(60, 60);
frm.Controls.Add(pb);
//移动的背景
while (frm.Created)
{
frm.Render();
Application.DoEvents();
}
}
}
private void InitializeComponent()
{
this.SuspendLayout();
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(400, 200);
this.Name = "MDX4";
this.ResumeLayout(false);
}
}
}

Forty2 2017-03-22
  • 打赏
  • 举报
回复
PictureBox是方便显示图像的一个容器,但是,显示图像却不需要一定用PictureBox。 当PictureBox阻碍你实现一定效果时,就不要死抱着它不放。 如下例子,你要创建一个新的WinForm项目,打开Form1.cs,然后帖入代码,F5就可运行观察效果:
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    /////// 沾贴如下代码
    protected override void OnLoad(EventArgs e)
    {
        this.DoubleBuffered = true;
        try
        {
            var url = "https://img-bbs.csdn.net/upload/201703/21/1490080881_639835.jpg";
            var bytes = new WebClient().DownloadData(url);
            farBackground = Image.FromStream(new System.IO.MemoryStream(bytes)) as Bitmap;
            nearBackground = CreateNearBackGround(farBackground.Width, farBackground.Height);
        }
        catch { }
        timer.Tick += delegate
        {
            if (farBackground == null) return;
            offsetFar = (offsetFar + 2) % farBackground.Width;
            offsetNear = (offsetNear + 5) % farBackground.Width;
            this.Invalidate();
        };
        timer.Enabled = true;
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        if (farBackground != null) e.Graphics.DrawImage(farBackground, -offsetFar, 0);
        if (nearBackground != null) e.Graphics.DrawImage(nearBackground, -offsetNear, 0);
        if (train != null) e.Graphics.DrawImage(train, 130, 180);
    }
    Bitmap CreateNearBackGround(int width, int height)
    {
        Bitmap bmp = new Bitmap(width, height);
        using (var g = Graphics.FromImage(bmp))
        {
            Random r = new Random();
            for (int i = 0; i < 30; i++)
            {
                g.DrawIcon(SystemIcons.Question, r.Next(width), r.Next(height));
            }
        }
        return bmp;
    }
    Bitmap farBackground, nearBackground, train = SystemIcons.Error.ToBitmap();
    int offsetFar, offsetNear;
    Timer timer = new System.Windows.Forms.Timer() { Interval = 25 };
    /////// 沾贴如上代码
}
以上是WinForm代码。但总的来说,动画上用WPF更好做一些。你要认真考虑是否用WPF来做。
qq_36198178 2017-03-22
  • 打赏
  • 举报
回复
引用 34 楼 xuggzu 的回复:
不论什么项目,在选择开发工具或者编码语言或者辅助工具或者框架,基本原则是:只选对的不选累的。
兄弟,谢谢您啊!虽然自己还比较水,很水很水的那种,可能有时候你们觉得很简单的事,我得试半天,而且还不一定能弄出来,但还是很感激您帮忙想办法!
qq_36198178 2017-03-22
  • 打赏
  • 举报
回复
引用 41 楼 Forty2 的回复:
PictureBox是方便显示图像的一个容器,但是,显示图像却不需要一定用PictureBox。 当PictureBox阻碍你实现一定效果时,就不要死抱着它不放。 如下例子,你要创建一个新的WinForm项目,打开Form1.cs,然后帖入代码,F5就可运行观察效果:
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    /////// 沾贴如下代码
    protected override void OnLoad(EventArgs e)
    {
        this.DoubleBuffered = true;
        try
        {
            var url = "https://img-bbs.csdn.net/upload/201703/21/1490080881_639835.jpg";
            var bytes = new WebClient().DownloadData(url);
            farBackground = Image.FromStream(new System.IO.MemoryStream(bytes)) as Bitmap;
            nearBackground = CreateNearBackGround(farBackground.Width, farBackground.Height);
        }
        catch { }
        timer.Tick += delegate
        {
            if (farBackground == null) return;
            offsetFar = (offsetFar + 2) % farBackground.Width;
            offsetNear = (offsetNear + 5) % farBackground.Width;
            this.Invalidate();
        };
        timer.Enabled = true;
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        if (farBackground != null) e.Graphics.DrawImage(farBackground, -offsetFar, 0);
        if (nearBackground != null) e.Graphics.DrawImage(nearBackground, -offsetNear, 0);
        if (train != null) e.Graphics.DrawImage(train, 130, 180);
    }
    Bitmap CreateNearBackGround(int width, int height)
    {
        Bitmap bmp = new Bitmap(width, height);
        using (var g = Graphics.FromImage(bmp))
        {
            Random r = new Random();
            for (int i = 0; i < 30; i++)
            {
                g.DrawIcon(SystemIcons.Question, r.Next(width), r.Next(height));
            }
        }
        return bmp;
    }
    Bitmap farBackground, nearBackground, train = SystemIcons.Error.ToBitmap();
    int offsetFar, offsetNear;
    Timer timer = new System.Windows.Forms.Timer() { Interval = 25 };
    /////// 沾贴如上代码
}
以上是WinForm代码。但总的来说,动画上用WPF更好做一些。你要认真考虑是否用WPF来做。
谢谢您啊!虽然代码我只能看懂一部分,主要是我太水了,很感谢您抽出时间来帮我想办法!
qq_36198178 2017-03-22
  • 打赏
  • 举报
回复
引用 42 楼 xuzuning 的回复:
把 SizeMode 的 Zoom 去掉
真的可以了 感激之情无以言表 谢谢您啊!
xuzuning 2017-03-22
  • 打赏
  • 举报
回复
把 SizeMode 的 Zoom 去掉
xuggzu 2017-03-21
  • 打赏
  • 举报
回复
不论什么项目,在选择开发工具或者编码语言或者辅助工具或者框架,基本原则是:只选对的不选累的。
good_jobs 2017-03-21
  • 打赏
  • 举报
回复
大方向就是错的,这种需求不能用picbox。 用GDI+分层绘制。
qq_36198178 2017-03-21
  • 打赏
  • 举报
回复
引用 39 楼 xuzuning 的回复:
没有问题呀

我不管怎样试,都是这样:

难道是我pictureBox设置有问题吗?我就是普通的设置啊:


我就简简单单的设置两个pictureBox都还是这样,代码如下:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
pictureBox2.Region = GetRegion((Bitmap)pictureBox2.Image);
}
public Region GetRegion(Bitmap bmp)
{
Region res = new Region();
res.MakeEmpty();
var colorTransparent = bmp.GetPixel(0, 0); //指定左上角为透明色

var a = Enumerable.Range(0, bmp.Width).ToList();
var b = Enumerable.Range(0, bmp.Height).ToList();
var q = from x in a
from y in b
where bmp.GetPixel(x, y) != colorTransparent
select new Rectangle(x, y, 1, 1);
foreach (var r in q) res.Union(r);
return res;
}
}
xuzuning 2017-03-21
  • 打赏
  • 举报
回复
没有问题呀
qq_36198178 2017-03-21
  • 打赏
  • 举报
回复
引用 37 楼 xuzuning 的回复:

三张图片分别如下:
————————————分割线



————————————分割线



————————————分割线
xuzuning 2017-03-21
  • 打赏
  • 举报
回复
xuzuning 2017-03-21
  • 打赏
  • 举报
回复
不应该呀 你把你那个图片贴出来我看看
qq_36198178 2017-03-21
  • 打赏
  • 举报
回复
引用 29 楼 xuzuning 的回复:
        public Region GetRegion(Bitmap bmp)
{
Region res = new Region();
res.MakeEmpty();
var colorTransparent = bmp.GetPixel(0, 0); //指定左上角为透明色

var a = Enumerable.Range(0, bmp.Width).ToList();
var b = Enumerable.Range(0, bmp.Height).ToList();
var q = from x in a
from y in b
where bmp.GetPixel(x, y) != colorTransparent
select new Rectangle(x, y, 1, 1);
foreach (var r in q) res.Union(r);
return res;
}

你指定
pictureBox1.Region = GetRegion((Bitmap)pictureBox1.Image);
就可以了

不喜欢 linq 的话,就改成双重循环。看着还简单些

版主 还是得冒昧问一下:picture1变成这样的话,还应该怎样改啊?
xdashewan 2017-03-20
  • 打赏
  • 举报
回复
引用 11 楼 qq_36198178 的回复:
这样应该怎样设置车图片的背景透明呢?
你可以参照版主的使用gdi+或者gdi画,也可以把列车pic1也弄成两张,控制的方法和你背景一样
加载更多回复(31)

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧