public static void Draw(this GraphicResource res, Canvas c, int frame, float x, float y, Alignment alignment, ColorRgba color, float scaleX = 1f, float scaleY = 1f) { Texture texture = res.Material.Res.MainTexture.Res; if (texture == null) { return; } if (frame < 0) { // ToDo: HUD Animations are slowed down to 0.86f, adjust this in Metadata files frame = (int)(Time.GameTimer.TotalSeconds * 0.86f * res.FrameCount / res.FrameDuration) % res.FrameCount; } Rect uv = texture.LookupAtlas(frame); float w = texture.InternalWidth * scaleX * uv.W; float h = texture.InternalHeight * scaleY * uv.H; Vector2 originPos = new Vector2(x, y); alignment.ApplyTo(ref originPos, new Vector2(w, h)); c.State.SetMaterial(res.Material); c.State.ColorTint = color; c.State.TextureCoordinateRect = uv; c.FillRect((int)originPos.X, (int)originPos.Y, w, h); }
protected bool SetTransition(AnimState state, bool cancellable, Action callback = null) { List <GraphicResource> candidates = FindAnimationCandidates(state); if (candidates.Count == 0) { // ToDo: Cancel previous transition here? if (callback != null) { callback(); } return(false); } else { if (currentTransitionCallback != null) { Action oldCallback = currentTransitionCallback; currentTransitionCallback = null; oldCallback(); } currentTransitionCallback = callback; currentTransitionState = state; currentTransitionCancellable = cancellable; currentTransition = candidates[0]; RefreshAnimation(); return(true); } }
public void CreateSpriteDebris(GraphicResource res, Vector3 pos, int count) { Material material = res.Material.Res; Texture texture = material.MainTexture.Res; float x = pos.X - res.Base.Hotspot.X; float y = pos.Y - res.Base.Hotspot.Y; for (int i = 0; i < count; i++) { float speedX = MathF.Rnd.NextFloat(-1f, 1f) * MathF.Rnd.NextFloat(0.2f, 0.8f) * count; debrisList.Add(new DestructibleDebris { Pos = new Vector3(x, y, pos.Z), Size = res.Base.FrameDimensions, Speed = new Vector2(speedX, -1f * MathF.Rnd.NextFloat(2.2f, 4f)), Acceleration = new Vector2(0f, 0.2f), Scale = 1f, ScaleSpeed = -0.002f, Angle = MathF.Rnd.NextFloat(MathF.TwoPi), AngleSpeed = speedX * 0.02f, Alpha = 1f, AlphaSpeed = -0.002f, Time = 560f, Material = material, MaterialOffset = texture.LookupAtlas(res.FrameOffset + MathF.Rnd.Next(res.FrameCount)), CollisionAction = DebrisCollisionAction.Bounce }); } }
private void RefreshAnimation() { GraphicResource resource = (currentTransitionState != AnimState.Idle ? currentTransition : currentAnimation); if (renderer == null) { renderer = AddComponent <ActorRenderer>(); renderer.AnimationFinished = OnAnimationFinished; renderer.AlignToPixelGrid = true; renderer.Offset = -2000; renderer.Flip = (isFacingLeft ? SpriteRenderer.FlipMode.Horizontal : SpriteRenderer.FlipMode.None); } renderer.SharedMaterial = resource.Material; renderer.FrameConfiguration = resource.Base.FrameConfiguration; if (float.IsInfinity(resource.FrameDuration)) { if (resource.FrameCount > 1) { renderer.AnimFirstFrame = resource.FrameOffset + MathF.Rnd.Next(resource.FrameCount); } else { renderer.AnimFirstFrame = resource.FrameOffset; } renderer.AnimLoopMode = ActorRenderer.LoopMode.FixedSingle; } else { renderer.AnimFirstFrame = resource.FrameOffset; renderer.AnimLoopMode = (resource.OnlyOnce ? ActorRenderer.LoopMode.Once : ActorRenderer.LoopMode.Loop); } renderer.AnimFrameCount = resource.FrameCount; renderer.AnimDuration = resource.FrameDuration; renderer.Rect = new Rect( -resource.Base.Hotspot.X, -resource.Base.Hotspot.Y, resource.Base.FrameDimensions.X, resource.Base.FrameDimensions.Y ); renderer.AnimTime = 0; OnAnimationStarted(); if ((collisionFlags & CollisionFlags.SkipPerPixelCollisions) == 0) { // ToDo: Workaround for refresh of AABB Transform.Pos = Transform.Pos; } }
protected bool SetAnimation(AnimState state) { if (currentTransitionState != AnimState.Idle && !currentTransitionCancellable) { return(false); } if (currentAnimation?.State != null && currentAnimation.State.Contains(state)) { currentAnimationState = state; return(false); } List <GraphicResource> candidates = FindAnimationCandidates(state); if (candidates.Count == 0) { return(false); } else { if (currentTransitionState != AnimState.Idle) { currentTransitionState = AnimState.Idle; if (currentTransitionCallback != null) { Action oldCallback = currentTransitionCallback; currentTransitionCallback = null; oldCallback(); } } currentAnimationState = state; if (candidates.Count > 1) { currentAnimation = candidates[MathF.Rnd.Next() % candidates.Count]; } else { currentAnimation = candidates[0]; } if (boundingBox.X == 0 || boundingBox.Y == 0) { boundingBox = currentAnimation.Base.FrameDimensions - new Point2(2, 2); } RefreshAnimation(); return(true); } }
protected void SetAnimation(string identifier) { currentAnimationState = AnimState.Idle; currentAnimation = availableAnimations[identifier]; // ToDo: Remove this bounding box reduction // ToDo: Move bounding box calculation to Import project if (boundingBox.X == 0 || boundingBox.Y == 0) { boundingBox = currentAnimation.Base.FrameDimensions - new Point2(4, 0); } RefreshAnimation(); }
// GraphicResources public static void Draw(this GraphicResource res, Canvas c, float x, float y, Alignment alignment, ColorRgba color, float scaleX = 1f, float scaleY = 1f) { Texture texture = res.Material.Res.MainTexture.Res; if (texture == null) { return; } Vector2 originPos = new Vector2(x, y); alignment.ApplyTo(ref originPos, new Vector2(texture.InternalWidth * scaleX, texture.InternalHeight * scaleY)); c.State.SetMaterial(res.Material); c.State.ColorTint = color; c.FillRect((int)originPos.X, (int)originPos.Y, texture.InternalWidth * scaleX, texture.InternalHeight * scaleY); }
public override void OnFixedUpdate(float timeMult) { if (cooldown > 0f) { cooldown -= timeMult; } else { GraphicResource res = availableAnimations["AmbientBubbles"]; Material material = res.Material.Res; Texture texture = material.MainTexture.Res; for (int i = 0; i < speed; i++) { float scale = MathF.Rnd.NextFloat(0.3f, 1.0f); float speedX = MathF.Rnd.NextFloat(-0.5f, 0.5f) * scale; float speedY = MathF.Rnd.NextFloat(-3f, -2f) * scale; float accel = MathF.Rnd.NextFloat(-0.008f, -0.001f) * scale; levelHandler.TileMap.CreateDebris(new TileMap.DestructibleDebris { Pos = Transform.Pos, Size = res.Base.FrameDimensions, Speed = new Vector2(speedX, speedY), Acceleration = new Vector2(0f, accel), Scale = scale, Alpha = 1f, AlphaSpeed = -0.009f, Time = 110f, Material = material, MaterialOffset = texture.LookupAtlas(res.FrameOffset + MathF.Rnd.Next(res.FrameCount)), CollisionAction = TileMap.DebrisCollisionAction.None }); } cooldown = 20f; } }
public void CreateParticleDebris(GraphicResource res, Vector3 pos, Vector2 force, int currentFrame, bool isFacingLeft) { const int debrisSize = 3; Material material = res.Material.Res; Texture texture = material.MainTexture.Res; float x = pos.X - res.Base.Hotspot.X; float y = pos.Y - res.Base.Hotspot.Y; for (int fx = 0; fx < res.Base.FrameDimensions.X; fx += debrisSize + 1) { for (int fy = 0; fy < res.Base.FrameDimensions.Y; fy += debrisSize + 1) { float currentSize = debrisSize * MathF.Rnd.NextFloat(0.2f, 1.1f); debrisList.Add(new DestructibleDebris { Pos = new Vector3(x + (isFacingLeft ? res.Base.FrameDimensions.X - fx : fx), y + fy, pos.Z), Size = new Vector2(currentSize /** (isFacingLeft ? -1f : 1f)*/, currentSize), Speed = new Vector2(force.X + ((fx - res.Base.FrameDimensions.X / 2) + MathF.Rnd.NextFloat(-2f, 2f)) * (isFacingLeft ? -1f : 1f) * MathF.Rnd.NextFloat(2f, 8f) / res.Base.FrameDimensions.X, force.Y - 1f * MathF.Rnd.NextFloat(2.2f, 4f)), Acceleration = new Vector2(0f, 0.2f), Scale = 1f, Alpha = 1f, AlphaSpeed = -0.002f, Time = 320f, Material = material, MaterialOffset = new Rect( (((float)(currentFrame % res.Base.FrameConfiguration.X) / res.Base.FrameConfiguration.X) + ((float)fx / texture.ContentWidth)) * texture.UVRatio.X, (((float)(currentFrame / res.Base.FrameConfiguration.X) / res.Base.FrameConfiguration.Y) + ((float)fy / texture.ContentHeight)) * texture.UVRatio.Y, (currentSize * texture.UVRatio.X / texture.ContentWidth), (currentSize * texture.UVRatio.Y / texture.ContentHeight) ), CollisionAction = DebrisCollisionAction.Bounce }); } } }
protected bool SetTransition(AnimState state, bool cancellable, Action callback = null) { List <GraphicResource> candidates = FindAnimationCandidates(state); if (candidates.Count == 0) { if (callback != null) { callback(); } return(false); } else { if (currentTransitionCallback != null) { Action oldCallback = currentTransitionCallback; currentTransitionCallback = null; oldCallback(); } currentTransitionCallback = callback; currentTransitionState = state; currentTransitionCancellable = cancellable; if (candidates.Count > 1) { currentTransition = candidates[MathF.Rnd.Next() % candidates.Count]; } else { currentTransition = candidates[0]; } RefreshAnimation(); return(true); } }
private Metadata RequestMetadataInner(string path, bool async) { //System.Diagnostics.Debug.WriteLine("Loading metadata \"" + path + "\"..."); #if UNCOMPRESSED_CONTENT string pathAbsolute = PathOp.Combine(DualityApp.DataDirectory, "Metadata", path + ".res"); #else string pathAbsolute = PathOp.Combine(DualityApp.DataDirectory, "Main.dz", "Metadata", path + ".res"); #endif MetadataJson json; using (Stream s = FileOp.Open(pathAbsolute, FileAccessMode.Read)) { lock (jsonParser) { json = jsonParser.Parse<MetadataJson>(s); } } Metadata metadata = new Metadata(); metadata.Referenced = true; metadata.AsyncFinalizingRequired = async; // Pre-load graphics if (json.Animations != null) { metadata.Graphics = new Dictionary<string, GraphicResource>(); foreach (KeyValuePair<string, MetadataJson.AnimationsSection> g in json.Animations) { if (g.Value.Path == null) { // No path provided, skip resource... continue; } #if !THROW_ON_MISSING_RESOURCES try { #endif bool isIndexed = (g.Value.Flags & 0x02) != 0x00; ColorRgba color; if (g.Value.ShaderColor == null || g.Value.ShaderColor.Count < 4) { color = (isIndexed ? new ColorRgba(0, 255) : ColorRgba.White); } else { color = new ColorRgba((byte)g.Value.ShaderColor[0], (byte)g.Value.ShaderColor[1], (byte)g.Value.ShaderColor[2], (byte)g.Value.ShaderColor[3]); } GenericGraphicResource resBase = RequestGraphicResource(g.Value.Path, async); // Create copy of generic resource GraphicResource res; if (async) { res = GraphicResource.From(resBase, g.Value.Shader, color, isIndexed); } else { ContentRef<DrawTechnique> drawTechnique; if (g.Value.Shader == null) { drawTechnique = (isIndexed ? paletteNormal : basicNormal); } else { drawTechnique = RequestShader(g.Value.Shader); } res = GraphicResource.From(resBase, drawTechnique, color, isIndexed, paletteTexture); } res.FrameOffset = g.Value.FrameOffset; string raw1, raw2; int raw3; if ((raw1 = g.Value.FrameCount as string) != null && int.TryParse(raw1, out raw3)) { res.FrameCount = raw3; } else { res.FrameCount -= res.FrameOffset; } if ((raw2 = g.Value.FrameRate as string) != null && int.TryParse(raw2, out raw3)) { res.FrameDuration = (raw3 <= 0 ? -1 : (1f / raw3) * 5); // ToDo: I don't know... } res.OnlyOnce = (g.Value.Flags & 0x01) != 0x00; if (g.Value.States != null) { res.State = new HashSet<AnimState>(); for (int i = 0; i < g.Value.States.Count; i++) { res.State.Add((AnimState)g.Value.States[i]); } } metadata.Graphics[g.Key] = res; #if !THROW_ON_MISSING_RESOURCES } catch (Exception ex) { #if !SERVER Log.Write(LogType.Warning, "Can't load animation \"" + g.Key + "\" from metadata \"" + path + "\": " + ex.Message); #endif } #endif } } #if !DISABLE_SOUND // Pre-load sounds if (json.Sounds != null) { metadata.Sounds = new Dictionary<string, SoundResource>(); foreach (var sound in json.Sounds) { if (sound.Value.Paths == null || sound.Value.Paths.Count == 0) { // No path provided, skip resource... continue; } #if !THROW_ON_MISSING_RESOURCES try { #endif IList<string> filenames = sound.Value.Paths; ContentRef<AudioData>[] data = new ContentRef<AudioData>[filenames.Count]; for (int i = 0; i < data.Length; i++) { #if UNCOMPRESSED_CONTENT using (Stream s = FileOp.Open(PathOp.Combine(DualityApp.DataDirectory, "Animations", filenames[i]), FileAccessMode.Read)) #else using (Stream s = FileOp.Open(PathOp.Combine(DualityApp.DataDirectory, "Main.dz", "Animations", filenames[i]), FileAccessMode.Read)) #endif { data[i] = new AudioData(s); } } SoundResource resource = new SoundResource(); resource.Sound = new Sound(data); metadata.Sounds[sound.Key] = resource; #if !THROW_ON_MISSING_RESOURCES } catch (Exception ex) { #if !SERVER Log.Write(LogType.Warning, "Can't load sound \"" + sound.Key + "\" from metadata \"" + path + "\": " + ex.Message); #endif } #endif } } #endif // Bounding Box if (json.BoundingBox != null && json.BoundingBox.Count == 2) { metadata.BoundingBox = new Point2(json.BoundingBox[0], json.BoundingBox[1]); } cachedMetadata[path] = metadata; // Request children if (json.Preload != null) { for (int i = 0; i < json.Preload.Count; i++) { PreloadAsync(json.Preload[i]); } } return metadata; }
protected virtual void OnFixedUpdate(float timeMult) { if (currentCarryOver.HasValue) { bool playersReady = true; foreach (Player player in players) { // Exit type is already provided playersReady &= player.OnLevelChanging(ExitType.None); } if (playersReady) { if (levelChangeTimer > 0) { levelChangeTimer -= timeMult; } else { root.ChangeLevel(currentCarryOver.Value); currentCarryOver = null; initState = InitState.Disposed; return; } } } if (difficulty != GameDifficulty.Multiplayer) { if (players.Count > 0) { Vector3 pos = players[0].Transform.Pos; int tx1 = (int)pos.X >> 5; int ty1 = (int)pos.Y >> 5; int tx2 = tx1; int ty2 = ty1; #if ENABLE_SPLITSCREEN for (int i = 1; i < players.Count; i++) { Vector3 pos2 = players[i].Transform.Pos; int tx = (int)pos2.X >> 5; int ty = (int)pos2.Y >> 5; if (tx1 > tx) { tx1 = tx; } else if (tx2 < tx) { tx2 = tx; } if (ty1 > ty) { ty1 = ty; } else if (ty2 < ty) { ty2 = ty; } } #endif // ToDo: Remove this branching #if __ANDROID__ const int ActivateTileRange = 20; #else const int ActivateTileRange = 26; #endif tx1 -= ActivateTileRange; ty1 -= ActivateTileRange; tx2 += ActivateTileRange; ty2 += ActivateTileRange; for (int i = 0; i < actors.Count; i++) { if (actors[i].OnTileDeactivate(tx1 - 2, ty1 - 2, tx2 + 2, ty2 + 2)) { i--; } } eventMap.ActivateEvents(tx1, ty1, tx2, ty2, initState != InitState.Initializing); } eventMap.ProcessGenerators(timeMult); } ResolveCollisions(); // Ambient Light Transition if (ambientLightCurrent != ambientLightTarget) { float step = timeMult * 0.012f; if (MathF.Abs(ambientLightCurrent - ambientLightTarget) < step) { ambientLightCurrent = ambientLightTarget; } else { ambientLightCurrent += step * ((ambientLightTarget < ambientLightCurrent) ? -1 : 1); } } // Weather if (weatherType != WeatherType.None && commonResources.Graphics != null) { // ToDo: Apply weather effect to all other cameras too Vector3 viewPos = cameras[0].Transform.Pos; for (int i = 0; i < weatherIntensity; i++) { TileMap.DebrisCollisionAction collisionAction; if (weatherOutdoors) { collisionAction = TileMap.DebrisCollisionAction.Disappear; } else { collisionAction = (MathF.Rnd.NextFloat() > 0.7f ? TileMap.DebrisCollisionAction.None : TileMap.DebrisCollisionAction.Disappear); } Vector3 debrisPos = viewPos + MathF.Rnd.NextVector3((LevelRenderSetup.TargetSize.X / -2) - 40, (LevelRenderSetup.TargetSize.Y * -2 / 3), MainPlaneZ, LevelRenderSetup.TargetSize.X + 120, LevelRenderSetup.TargetSize.Y, 0); if (weatherType == WeatherType.Rain) { GraphicResource res = commonResources.Graphics["Rain"]; Material material = res.Material.Res; Texture texture = material.MainTexture.Res; float scale = MathF.Rnd.NextFloat(0.4f, 1.1f); float speedX = MathF.Rnd.NextFloat(2.2f, 2.7f) * scale; float speedY = MathF.Rnd.NextFloat(7.6f, 8.6f) * scale; debrisPos.Z = MainPlaneZ * scale; tileMap.CreateDebris(new TileMap.DestructibleDebris { Pos = debrisPos, Size = res.Base.FrameDimensions, Speed = new Vector2(speedX, speedY), Scale = scale, Angle = MathF.Atan2(speedY, speedX), Alpha = 1f, Time = 180f, Material = material, MaterialOffset = texture.LookupAtlas(res.FrameOffset + MathF.Rnd.Next(res.FrameCount)), CollisionAction = collisionAction }); } else { GraphicResource res = commonResources.Graphics["Snow"]; Material material = res.Material.Res; Texture texture = material.MainTexture.Res; float scale = MathF.Rnd.NextFloat(0.4f, 1.1f); float speedX = MathF.Rnd.NextFloat(-1.6f, -1.2f) * scale; float speedY = MathF.Rnd.NextFloat(3f, 4f) * scale; float accel = MathF.Rnd.NextFloat(-0.008f, 0.008f) * scale; debrisPos.Z = MainPlaneZ * scale; tileMap.CreateDebris(new TileMap.DestructibleDebris { Pos = debrisPos, Size = res.Base.FrameDimensions, Speed = new Vector2(speedX, speedY), Acceleration = new Vector2(accel, -MathF.Abs(accel)), Scale = scale, Angle = MathF.Rnd.NextFloat(MathF.TwoPi), AngleSpeed = speedX * 0.02f, Alpha = 1f, Time = 180f, Material = material, MaterialOffset = texture.LookupAtlas(res.FrameOffset + MathF.Rnd.Next(res.FrameCount)), CollisionAction = collisionAction }); } } } // Active Boss if (activeBoss != null && activeBoss.Scene == null) { activeBoss = null; Hud hud = rootObject.GetComponent <Hud>(); if (hud != null) { hud.ActiveBoss = null; } InitLevelChange(ExitType.Normal, null); levelChangeTimer = 300; } if (initState == InitState.Initializing) { initState = InitState.Initialized; } collisionsCountA = 0; collisionsCountB = 0; collisionsCountC = 0; }
private bool IsCollidingWithAngled(ActorBase other) { const byte AlphaThreshold = 40; GraphicResource res1 = (currentTransitionState != AnimState.Idle ? currentTransition : currentAnimation); GraphicResource res2 = (other.currentTransitionState != AnimState.Idle ? other.currentTransition : other.currentAnimation); PixelData p1 = res1?.Material.Res?.MainTexture.Res?.BasePixmap.Res.PixelData?[0]; PixelData p2 = res2?.Material.Res?.MainTexture.Res?.BasePixmap.Res.PixelData?[0]; if (p1 == null || p2 == null) { return(false); } Matrix4 transform1 = Matrix4.CreateTranslation(new Vector3(-res1.Base.Hotspot.X, -res1.Base.Hotspot.Y, 0f)); if (isFacingLeft) { transform1 *= Matrix4.CreateScale(-1f, 1f, 1f); } transform1 *= Matrix4.CreateRotationZ(Transform.Angle) * Matrix4.CreateTranslation(Transform.Pos); Matrix4 transform2 = Matrix4.CreateTranslation(new Vector3(-res2.Base.Hotspot.X, -res2.Base.Hotspot.Y, 0f)); if (other.isFacingLeft) { transform2 *= Matrix4.CreateScale(-1f, 1f, 1f); } transform2 *= Matrix4.CreateRotationZ(other.Transform.Angle) * Matrix4.CreateTranslation(other.Transform.Pos); int width1 = res1.Base.FrameDimensions.X; int height1 = res1.Base.FrameDimensions.Y; int width2 = res2.Base.FrameDimensions.X; int height2 = res2.Base.FrameDimensions.Y; // Bounding Box intersection Hitbox box1, box2; { Vector2 tl = Vector2.Transform(Vector2.Zero, transform1); Vector2 tr = Vector2.Transform(new Vector2(width1, 0f), transform1); Vector2 bl = Vector2.Transform(new Vector2(0f, height1), transform1); Vector2 br = Vector2.Transform(new Vector2(width1, height1), transform1); float minX = MathF.Min(tl.X, tr.X, bl.X, br.X); float minY = MathF.Min(tl.Y, tr.Y, bl.Y, br.Y); float maxX = MathF.Max(tl.X, tr.X, bl.X, br.X); float maxY = MathF.Max(tl.Y, tr.Y, bl.Y, br.Y); box1 = new Hitbox( MathF.Floor(minX), MathF.Floor(minY), MathF.Ceiling(maxX), MathF.Ceiling(maxY)); } { Vector2 tl = Vector2.Transform(Vector2.Zero, transform2); Vector2 tr = Vector2.Transform(new Vector2(width2, 0f), transform2); Vector2 bl = Vector2.Transform(new Vector2(0f, height2), transform2); Vector2 br = Vector2.Transform(new Vector2(width2, height2), transform2); float minX = MathF.Min(tl.X, tr.X, bl.X, br.X); float minY = MathF.Min(tl.Y, tr.Y, bl.Y, br.Y); float maxX = MathF.Max(tl.X, tr.X, bl.X, br.X); float maxY = MathF.Max(tl.Y, tr.Y, bl.Y, br.Y); box2 = new Hitbox( MathF.Floor(minX), MathF.Floor(minY), MathF.Ceiling(maxX), MathF.Ceiling(maxY)); } if (!box1.Intersects(ref box2)) { return(false); } // Per-pixel collision check Matrix4 transformAToB = transform1 * Matrix4.Invert(transform2); // TransformNormal with [1, 0] and [0, 1] vectors Vector2 stepX = new Vector2(transformAToB.M11, transformAToB.M12); Vector2 stepY = new Vector2(transformAToB.M21, transformAToB.M22); Vector2 yPosIn2 = Vector2.Transform(Vector2.Zero, transformAToB); int frame1 = MathF.Min(renderer.CurrentFrame, res1.FrameCount - 1); int dx1 = (frame1 % res1.Base.FrameConfiguration.X) * res1.Base.FrameDimensions.X; int dy1 = (frame1 / res1.Base.FrameConfiguration.X) * res1.Base.FrameDimensions.Y; int frame2 = MathF.Min(other.renderer.CurrentFrame, res2.FrameCount - 1); int dx2 = (frame2 % res2.Base.FrameConfiguration.X) * res2.Base.FrameDimensions.X; int dy2 = (frame2 / res2.Base.FrameConfiguration.X) * res2.Base.FrameDimensions.Y; for (int y1 = 0; y1 < height1; y1++) { Vector2 posIn2 = yPosIn2; for (int x1 = 0; x1 < width1; x1++) { int x2 = (int)MathF.Round(posIn2.X); int y2 = (int)MathF.Round(posIn2.Y); if (x2 >= 0 && x2 < width2 && y2 >= 0 && y2 < height2) { if (p1[x1 + dx1, y1 + dy1].A > AlphaThreshold && p2[x2 + dx2, y2 + dy2].A > AlphaThreshold) { return(true); } } posIn2 += stepX; } yPosIn2 += stepY; } return(false); }
public bool IsCollidingWith(ActorBase other) { const byte AlphaThreshold = 40; bool perPixel1 = (collisionFlags & CollisionFlags.SkipPerPixelCollisions) == 0; bool perPixel2 = (other.collisionFlags & CollisionFlags.SkipPerPixelCollisions) == 0; // Limitation - both have to support per-pixel collisions if (perPixel1 && perPixel2 && (Transform.Angle != 0f || other.Transform.Angle != 0f)) { return(IsCollidingWithAngled(other)); } GraphicResource res1 = (currentTransitionState != AnimState.Idle ? currentTransition : currentAnimation); GraphicResource res2 = (other.currentTransitionState != AnimState.Idle ? other.currentTransition : other.currentAnimation); PixelData p1 = res1?.Material.Res?.MainTexture.Res?.BasePixmap.Res.PixelData?[0]; PixelData p2 = res2?.Material.Res?.MainTexture.Res?.BasePixmap.Res.PixelData?[0]; if (p1 == null || p2 == null) { return(false); } Vector3 pos1 = Transform.Pos; Vector3 pos2 = other.Transform.Pos; Point2 hotspot1 = res1.Base.Hotspot; Point2 hotspot2 = res2.Base.Hotspot; Point2 size1 = res1.Base.FrameDimensions; Point2 size2 = res2.Base.FrameDimensions; Rect box1, box2; if (!perPixel1) { box1 = new Rect(currentHitbox.Left, currentHitbox.Top, currentHitbox.Right - currentHitbox.Left, currentHitbox.Bottom - currentHitbox.Top); } else if (isFacingLeft) { box1 = new Rect(pos1.X + hotspot1.X - size1.X, pos1.Y - hotspot1.Y, size1.X, size1.Y); } else { box1 = new Rect(pos1.X - hotspot1.X, pos1.Y - hotspot1.Y, size1.X, size1.Y); } if (!perPixel2) { box2 = new Rect(other.currentHitbox.Left, other.currentHitbox.Top, other.currentHitbox.Right - other.currentHitbox.Left, other.currentHitbox.Bottom - other.currentHitbox.Top); } else if (other.isFacingLeft) { box2 = new Rect(pos2.X + hotspot2.X - size2.X, pos2.Y - hotspot2.Y, size2.X, size2.Y); } else { box2 = new Rect(pos2.X - hotspot2.X, pos2.Y - hotspot2.Y, size2.X, size2.Y); } // Bounding Box intersection Rect inter = box1.Intersection(box2); if (inter.W <= 0 || inter.H <= 0) { return(false); } if (!perPixel1 || !perPixel2) { if (perPixel1 == perPixel2) { return(true); } PixelData p; GraphicResource res; bool isFacingLeftCurrent; int x1, y1, x2, y2, xs, dx, dy; if (perPixel1) { p = p1; res = res1; isFacingLeftCurrent = isFacingLeft; x1 = (int)MathF.Max(inter.X, other.currentHitbox.Left); y1 = (int)MathF.Max(inter.Y, other.currentHitbox.Top); x2 = (int)MathF.Min(inter.RightX, other.currentHitbox.Right); y2 = (int)MathF.Min(inter.BottomY, other.currentHitbox.Bottom); xs = (int)box1.X; int frame1 = Math.Min(renderer.CurrentFrame, res.FrameCount - 1); dx = (frame1 % res.Base.FrameConfiguration.X) * res.Base.FrameDimensions.X; dy = (frame1 / res.Base.FrameConfiguration.X) * res.Base.FrameDimensions.Y - (int)box1.Y; } else { p = p2; res = res2; isFacingLeftCurrent = other.isFacingLeft; x1 = (int)MathF.Max(inter.X, currentHitbox.Left); y1 = (int)MathF.Max(inter.Y, currentHitbox.Top); x2 = (int)MathF.Min(inter.RightX, currentHitbox.Right); y2 = (int)MathF.Min(inter.BottomY, currentHitbox.Bottom); xs = (int)box2.X; int frame2 = Math.Min(other.renderer.CurrentFrame, res.FrameCount - 1); dx = (frame2 % res.Base.FrameConfiguration.X) * res.Base.FrameDimensions.X; dy = (frame2 / res.Base.FrameConfiguration.X) * res.Base.FrameDimensions.Y - (int)box2.Y; } // Per-pixel collision check for (int i = x1; i < x2; i++) { for (int j = y1; j < y2; j++) { int i1 = i - xs; if (isFacingLeftCurrent) { i1 = res.Base.FrameDimensions.X - i1 - 1; } if (p[i1 + dx, j + dy].A > AlphaThreshold) { return(true); } } } } else { int x1 = (int)inter.X; int y1 = (int)inter.Y; int x2 = (int)inter.RightX; int y2 = (int)inter.BottomY; int x1s = (int)box1.X; int x2s = (int)box2.X; int frame1 = Math.Min(renderer.CurrentFrame, res1.FrameCount - 1); int dx1 = (frame1 % res1.Base.FrameConfiguration.X) * res1.Base.FrameDimensions.X; int dy1 = (frame1 / res1.Base.FrameConfiguration.X) * res1.Base.FrameDimensions.Y - (int)box1.Y; int frame2 = Math.Min(other.renderer.CurrentFrame, res2.FrameCount - 1); int dx2 = (frame2 % res2.Base.FrameConfiguration.X) * res2.Base.FrameDimensions.X; int dy2 = (frame2 / res2.Base.FrameConfiguration.X) * res2.Base.FrameDimensions.Y - (int)box2.Y; // Per-pixel collision check for (int i = x1; i < x2; i++) { for (int j = y1; j < y2; j++) { int i1 = i - x1s; if (isFacingLeft) { i1 = res1.Base.FrameDimensions.X - i1 - 1; } int i2 = i - x2s; if (other.isFacingLeft) { i2 = res2.Base.FrameDimensions.X - i2 - 1; } if (p1[i1 + dx1, j + dy1].A > AlphaThreshold && p2[i2 + dx2, j + dy2].A > AlphaThreshold) { return(true); } } } } return(false); }
internal void UpdateAABB() { if ((collisionFlags & (CollisionFlags.CollideWithOtherActors | CollisionFlags.CollideWithSolidObjects | CollisionFlags.IsSolidObject)) == 0) { // Collisions are deactivated return; } if ((collisionFlags & CollisionFlags.SkipPerPixelCollisions) == 0) { GraphicResource res = (currentTransitionState != AnimState.Idle ? currentTransition : currentAnimation); if (res == null) { return; } Vector3 pos = Transform.Pos; float timeMult = Time.TimeMult; pos.X += speedX * timeMult; pos.Y += speedY * timeMult; Point2 hotspot = res.Base.Hotspot; Point2 size = res.Base.FrameDimensions; if (Transform.Angle != 0f) { Matrix4 transform1 = Matrix4.CreateTranslation(new Vector3(-hotspot.X, -hotspot.Y, 0f)); if (isFacingLeft) { transform1 *= Matrix4.CreateScale(-1f, 1f, 1f); } transform1 *= Matrix4.CreateRotationZ(Transform.Angle) * Matrix4.CreateTranslation(pos); Vector2 tl = Vector2.Transform(Vector2.Zero, transform1); Vector2 tr = Vector2.Transform(new Vector2(size.X, 0f), transform1); Vector2 bl = Vector2.Transform(new Vector2(0f, size.Y), transform1); Vector2 br = Vector2.Transform(new Vector2(size.X, size.Y), transform1); float minX = MathF.Min(tl.X, tr.X, bl.X, br.X); float minY = MathF.Min(tl.Y, tr.Y, bl.Y, br.Y); float maxX = MathF.Max(tl.X, tr.X, bl.X, br.X); float maxY = MathF.Max(tl.Y, tr.Y, bl.Y, br.Y); AABB.LowerBound = new Vector2(minX, minY); AABB.UpperBound = new Vector2(maxX, maxY); } else { if (isFacingLeft) { AABB.LowerBound = new Vector2(pos.X + hotspot.X - size.X, pos.Y - hotspot.Y); } else { AABB.LowerBound = new Vector2(pos.X - hotspot.X, pos.Y - hotspot.Y); } AABB.UpperBound = AABB.LowerBound + size; } } else { OnUpdateHitbox(); AABB = currentHitbox.ToAABB(); } #if DEBUG Game.UI.Hud.ShowDebugRect(new Rect(AABB.LowerBound.X, AABB.LowerBound.Y, AABB.UpperBound.X - AABB.LowerBound.X, AABB.UpperBound.Y - AABB.LowerBound.Y)); #endif }
private void FinalizeAsyncLoadedResources(Metadata metadata) { if (metadata.Graphics != null) { foreach (var pair in metadata.Graphics) { GraphicResource res = pair.Value; GenericGraphicResource resBase = res.Base; if (resBase.AsyncFinalize != null) { TextureMagFilter magFilter; TextureMinFilter minFilter; if (resBase.AsyncFinalize.LinearSampling) { magFilter = TextureMagFilter.Linear; minFilter = TextureMinFilter.LinearMipmapLinear; } else { magFilter = TextureMagFilter.Nearest; minFilter = TextureMinFilter.Nearest; } resBase.Texture = new Texture(resBase.AsyncFinalize.TextureMap, TextureSizeMode.NonPowerOfTwo, magFilter, minFilter, resBase.AsyncFinalize.TextureWrap, resBase.AsyncFinalize.TextureWrap); if (resBase.AsyncFinalize.TextureNormalMap != null) { resBase.TextureNormal = new Texture(resBase.AsyncFinalize.TextureNormalMap, TextureSizeMode.NonPowerOfTwo, magFilter, minFilter, resBase.AsyncFinalize.TextureWrap, resBase.AsyncFinalize.TextureWrap); } resBase.AsyncFinalize = null; } if (res.AsyncFinalize != null) { ContentRef <DrawTechnique> drawTechnique; if (res.AsyncFinalize.Shader == null) { drawTechnique = (res.AsyncFinalize.BindPaletteToMaterial ? paletteNormal : basicNormal); } else { drawTechnique = RequestShader(res.AsyncFinalize.Shader); } Material material = new Material(drawTechnique, res.AsyncFinalize.Color); material.SetTexture("mainTex", resBase.Texture); if (resBase.TextureNormal != null) { material.SetTexture("normalTex", resBase.TextureNormal); } if (res.AsyncFinalize.BindPaletteToMaterial) { material.SetTexture("paletteTex", paletteTexture); } res.Material = material; res.AsyncFinalize = null; } } } }
protected void CreateDeathDebris(ActorBase collider) { TileMap tilemap = levelHandler.TileMap; if (tilemap == null) { return; } Vector3 pos = Transform.Pos; if (collider is AmmoToaster) { const int debrisSizeX = 5; const int debrisSizeY = 3; GraphicResource res = currentTransitionState != AnimState.Idle ? currentTransition : currentAnimation; Material material = res.Material.Res; Texture texture = material.MainTexture.Res; float x = pos.X - res.Base.Hotspot.X; float y = pos.Y - res.Base.Hotspot.Y; int currentFrame = renderer.CurrentFrame; for (int fx = 0; fx < res.Base.FrameDimensions.X; fx += debrisSizeX + 1) { for (int fy = 0; fy < res.Base.FrameDimensions.Y; fy += debrisSizeY + 1) { float currentSizeX = debrisSizeX * MathF.Rnd.NextFloat(0.8f, 1.1f); float currentSizeY = debrisSizeY * MathF.Rnd.NextFloat(0.8f, 1.1f); levelHandler.TileMap.CreateDebris(new DestructibleDebris { Pos = new Vector3(x + (IsFacingLeft ? res.Base.FrameDimensions.X - fx : fx), y + fy, pos.Z), Size = new Vector2(currentSizeX, currentSizeY), Speed = new Vector2(((fx - res.Base.FrameDimensions.X / 2) + MathF.Rnd.NextFloat(-2f, 2f)) * (IsFacingLeft ? -1f : 1f) * MathF.Rnd.NextFloat(0.5f, 2f) / res.Base.FrameDimensions.X, MathF.Rnd.NextFloat(0f, 0.2f)), Acceleration = new Vector2(0f, 0.06f), Scale = 1f, Alpha = 1f, AlphaSpeed = -0.002f, Time = 320f, Material = material, MaterialOffset = new Rect( (((float)(currentFrame % res.Base.FrameConfiguration.X) / res.Base.FrameConfiguration.X) + ((float)fx / texture.ContentWidth)) * texture.UVRatio.X, (((float)(currentFrame / res.Base.FrameConfiguration.X) / res.Base.FrameConfiguration.Y) + ((float)fy / texture.ContentHeight)) * texture.UVRatio.Y, (currentSizeX * texture.UVRatio.X / texture.ContentWidth), (currentSizeY * texture.UVRatio.Y / texture.ContentHeight) ), CollisionAction = DebrisCollisionAction.Bounce }); } } } else if (pos.Y > levelHandler.WaterLevel) { const int DebrisSize = 3; GraphicResource res = currentTransitionState != AnimState.Idle ? currentTransition : currentAnimation; Material material = res.Material.Res; Texture texture = material.MainTexture.Res; float x = pos.X - res.Base.Hotspot.X; float y = pos.Y - res.Base.Hotspot.Y; for (int fx = 0; fx < res.Base.FrameDimensions.X; fx += DebrisSize + 1) { for (int fy = 0; fy < res.Base.FrameDimensions.Y; fy += DebrisSize + 1) { float currentSize = DebrisSize * MathF.Rnd.NextFloat(0.2f, 1.1f); levelHandler.TileMap.CreateDebris(new DestructibleDebris { Pos = new Vector3(x + (IsFacingLeft ? res.Base.FrameDimensions.X - fx : fx), y + fy, pos.Z), Size = new Vector2(currentSize /** (isFacingLeft ? -1f : 1f)*/, currentSize), Speed = new Vector2(((fx - res.Base.FrameDimensions.X / 2) + MathF.Rnd.NextFloat(-2f, 2f)) * (IsFacingLeft ? -1f : 1f) * MathF.Rnd.NextFloat(1f, 3f) / res.Base.FrameDimensions.X, ((fy - res.Base.FrameDimensions.Y / 2) + MathF.Rnd.NextFloat(-2f, 2f)) * (IsFacingLeft ? -1f : 1f) * MathF.Rnd.NextFloat(1f, 3f) / res.Base.FrameDimensions.Y), Acceleration = new Vector2(0f, 0f), Scale = 1f, Alpha = 1f, AlphaSpeed = -0.004f, Time = 340f, Material = material, MaterialOffset = new Rect( (((float)(renderer.CurrentFrame % res.Base.FrameConfiguration.X) / res.Base.FrameConfiguration.X) + ((float)fx / texture.ContentWidth)) * texture.UVRatio.X, (((float)(renderer.CurrentFrame / res.Base.FrameConfiguration.X) / res.Base.FrameConfiguration.Y) + ((float)fy / texture.ContentHeight)) * texture.UVRatio.Y, (currentSize * texture.UVRatio.X / texture.ContentWidth), (currentSize * texture.UVRatio.Y / texture.ContentHeight) ), CollisionAction = DebrisCollisionAction.Disappear }); } } } else { Vector2 force; switch (lastHitDir) { case LastHitDirection.Left: force = new Vector2(-1.4f, 0f); break; case LastHitDirection.Right: force = new Vector2(1.4f, 0f); break; case LastHitDirection.Up: force = new Vector2(0f, -1.4f); break; case LastHitDirection.Down: force = new Vector2(0f, 1.4f); break; default: force = Vector2.Zero; break; } tilemap.CreateParticleDebris(currentTransitionState != AnimState.Idle ? currentTransition : currentAnimation, Transform.Pos, force, renderer.CurrentFrame, IsFacingLeft); } }
private void OnUpdate() { if (currentCarryOver.HasValue) { if (levelChangeTimer > 0) { levelChangeTimer -= Time.TimeMult; } else { root.ChangeLevel(currentCarryOver.Value); currentCarryOver = null; return; } } Vector3 pos = players[0].Transform.Pos; //int tx = (int)(pos.X / 32); //int ty = (int)(pos.Y / 32); int tx = (int)pos.X >> 5; int ty = (int)pos.Y >> 5; // ToDo: Remove this branching #if __ANDROID__ const int ActivateTileRange = 20; #else const int ActivateTileRange = 26; #endif for (int i = 0; i < actors.Count; i++) { if (actors[i].OnTileDeactivate(tx, ty, ActivateTileRange + 2)) { i--; } } eventMap.ActivateEvents(tx, ty, ActivateTileRange); eventMap.ProcessGenerators(); ResolveCollisions(); // Ambient Light Transition if (ambientLightCurrent != ambientLightTarget) { float step = Time.TimeMult * 0.012f; if (MathF.Abs(ambientLightCurrent - ambientLightTarget) < step) { ambientLightCurrent = ambientLightTarget; } else { ambientLightCurrent += step * ((ambientLightTarget < ambientLightCurrent) ? -1 : 1); } } // Weather if (weatherType != WeatherType.None) { Vector3 viewPos = camera.Transform.Pos; for (int i = 0; i < weatherIntensity; i++) { TileMap.DebrisCollisionAction collisionAction; if (weatherOutdoors) { collisionAction = TileMap.DebrisCollisionAction.Disappear; } else { collisionAction = (MathF.Rnd.NextFloat() > 0.7f ? TileMap.DebrisCollisionAction.None : TileMap.DebrisCollisionAction.Disappear); } Vector3 debrisPos = viewPos + MathF.Rnd.NextVector3((LevelRenderSetup.TargetSize.X / -2) - 40, (LevelRenderSetup.TargetSize.Y * -2 / 3), MainPlaneZ, LevelRenderSetup.TargetSize.X + 120, LevelRenderSetup.TargetSize.Y, 0); if (weatherType == WeatherType.Rain) { GraphicResource res = commonResources.Graphics["Rain"]; Material material = res.Material.Res; Texture texture = material.MainTexture.Res; float scale = MathF.Rnd.NextFloat(0.4f, 1.1f); float speedX = MathF.Rnd.NextFloat(2.2f, 2.7f) * scale; float speedY = MathF.Rnd.NextFloat(7.6f, 8.6f) * scale; debrisPos.Z = MainPlaneZ * scale; tileMap.CreateDebris(new TileMap.DestructibleDebris { Pos = debrisPos, Size = res.Base.FrameDimensions, Speed = new Vector2(speedX, speedY), Scale = scale, Angle = MathF.Atan2(speedY, speedX), Alpha = 1f, Time = 180f, Material = material, MaterialOffset = texture.LookupAtlas(res.FrameOffset + MathF.Rnd.Next(res.FrameCount)), CollisionAction = collisionAction }); } else { GraphicResource res = commonResources.Graphics["Snow"]; Material material = res.Material.Res; Texture texture = material.MainTexture.Res; float scale = MathF.Rnd.NextFloat(0.4f, 1.1f); float speedX = MathF.Rnd.NextFloat(-1.6f, -1.2f) * scale; float speedY = MathF.Rnd.NextFloat(3f, 4f) * scale; float accel = MathF.Rnd.NextFloat(-0.008f, 0.008f) * scale; debrisPos.Z = MainPlaneZ * scale; tileMap.CreateDebris(new TileMap.DestructibleDebris { Pos = debrisPos, Size = res.Base.FrameDimensions, Speed = new Vector2(speedX, speedY), Acceleration = new Vector2(accel, -MathF.Abs(accel)), Scale = scale, Angle = MathF.Rnd.NextFloat(MathF.TwoPi), AngleSpeed = speedX * 0.02f, Alpha = 1f, Time = 180f, Material = material, MaterialOffset = texture.LookupAtlas(res.FrameOffset + MathF.Rnd.Next(res.FrameCount)), CollisionAction = collisionAction }); } } } // Active Boss if (activeBoss != null && activeBoss.ParentScene == null) { activeBoss = null; Hud hud = rootObject.GetComponent <Hud>(); if (hud != null) { hud.ActiveBoss = null; } InitLevelChange(ExitType.Normal, null); levelChangeTimer *= 2; } if (DualityApp.Keyboard.KeyHit(Key.Escape)) { Scene.SwitchTo(new InGameMenu(root, this)); } Hud.ShowDebugText("- FPS: " + Time.Fps.ToString("N0") + " (" + Math.Round(Time.UnscaledDeltaTime * 1000, 1).ToString("N1") + " ms)"); Hud.ShowDebugText(" Diff.: " + difficulty + " | Actors: " + actors.Count.ToString("N0")); Hud.ShowDebugText(" Ambient Light: " + ambientLightCurrent.ToString("0.00") + " / " + ambientLightTarget.ToString("0.00")); Hud.ShowDebugText(" Collisions: " + collisionsCountA + " > " + collisionsCountB + " > " + collisionsCountC); collisionsCountA = 0; collisionsCountB = 0; collisionsCountC = 0; }